home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / lib / jaq / dist / jupdate.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-11-06  |  24.9 KB  |  945 lines

  1. /* 
  2.  * jupdate.c --
  3.  *
  4.  *    Perform index jupdate on Jaquith archive system.
  5.  *
  6.  * Copyright 1991 Regents of the University of California
  7.  * Permission to use, copy, modify, and distribute this
  8.  * software and its documentation for any purpose and without
  9.  * fee is hereby granted, provided that the above copyright
  10.  * notice appear in all copies.  The University of California
  11.  * makes no representations about the suitability of this
  12.  * software for any purpose.  It is provided "as is" without
  13.  * express or implied warranty.
  14.  *
  15.  * Quote:
  16.  *     Bookkeeper: Mr. Goldwyn, our files are bulging with paperwork we no
  17.  *                 longer need.  May I have your permission to destroy all
  18.  *                 records before 1945?
  19.  *     Goldwyn:    Certainly.  Just be sure to keep a copy of everything.
  20.  *
  21.  */
  22.  
  23. #ifndef lint
  24. static char rcsid[] = "$Header: /sprite/lib/forms/RCS/jupdate.c,v 1.0 91/01/07 18:02:37 mottsmth Exp $ SPRITE (Berkeley)";
  25. #endif /* not lint */
  26.  
  27. #include "jaquith.h"
  28. #include "option.h"
  29.  
  30. static char  printBuf[T_MAXSTRINGLEN];
  31. static char *logPath;         /* pathname of log file */
  32. static FILE *memDbg = NULL;   /* stream for memory tracing */
  33.  
  34. int jDebug;                   /* Internal debugging only */
  35. int syserr = 0;               /* Our personal record of errno */
  36.  
  37. #define DEF_SOCK -1
  38. #define DEF_FLAGS 0
  39. #define DEF_DEBUG 0
  40. #define DEF_USER ""
  41. #define DEF_GROUP ""
  42. #define DEF_HOST ""
  43. #define DEF_DISKLOW 70
  44. #define DEF_DISKHIGH 80
  45. #define DEF_CLEANER ""
  46.  
  47. #define TBUFTARGETLEN 1024*T_TAPEUNIT
  48. #define METACHARS "*?,\\{}()[]"
  49.  
  50. typedef struct ReceiveBlk {
  51.     T_FileStat *statInfoPtr;
  52. } ReceiveBlk;
  53.  
  54. typedef struct parmTag {
  55.     int sock;
  56.     char *arch;
  57.     int flags;
  58.     char *root;
  59.     int debug;
  60.     int diskLow;
  61.     int diskHigh;
  62.     char *userName;
  63.     char *groupName;
  64.     char *hostName;
  65.     char *cleaner;
  66.     int fsyncFreq;
  67. } Parms;
  68.  
  69. Parms parms = {
  70.     DEF_SOCK,
  71.     DEF_ARCH,
  72.     DEF_FLAGS,
  73.     DEF_ROOT,
  74.     DEF_DEBUG,
  75.     DEF_DISKLOW,
  76.     DEF_DISKHIGH,
  77.     DEF_USER,
  78.     DEF_GROUP,
  79.     DEF_HOST,
  80.     DEF_CLEANER,
  81.     DEF_FSYNCFREQ
  82. };
  83.  
  84. static int   ReadOneFile      _ARGS_ ((int sock, int tBufStream, 
  85.                        int *byteCntPtr,
  86.                        T_FileStat *statInfoPtr));
  87. static int   FlushTBuf        _ARGS_ ((int tBufId, Parms *parmsPtr,
  88.                        char *archPath));
  89. static int   GetFileIndx      _ARGS_ ((T_FileStat *statInfoPtr,char *indxPath,
  90.                        char *archPath, Caller *callerPtr));
  91. static char *SortDirectoryList _ARGS_ ((char *list));
  92. static int   StringCompareProc _ARGS_ ((char **a, char **b));
  93. static int   ReceiveIndxProc   _ARGS_ ((T_FileStat *statInfoPtr,
  94.                     ReceiveBlk *receiveBlkPtr));
  95. static void  ReapChildren      _ARGS_ (());
  96. static int   VerifyClient      _ARGS_ ((char *archPath, int sock,
  97.                     Caller *callerPtr));
  98.  
  99. Option optionArray[] = {
  100.     {OPT_INT, "socket", (char *)&parms.sock, "socket #"},
  101.     {OPT_STRING, "archive", (char *)&parms.arch, "archive name"},
  102.     {OPT_INT, "flags", (char *)&parms.flags, "option flags"},
  103.     {OPT_STRING, "root", (char *)&parms.root, "root of index tree"},
  104.     {OPT_TRUE, "debug", (char *)&parms.debug, "enable debugging output"},
  105.     {OPT_INT, "disklow", (char *)&parms.diskLow, "Low usable disk (%)"},
  106.     {OPT_INT, "diskhigh", (char *)&parms.diskHigh, "High usable disk (%)"},
  107.     {OPT_STRING, "username", (char *)&parms.userName, "Name of requestor"},
  108.     {OPT_STRING, "groupname", (char *)&parms.groupName, "Group name of requestor"},
  109.     {OPT_STRING, "hostname", (char *)&parms.hostName, "Machine name of requestor"},
  110.     {OPT_STRING, "cleaner", (char *)&parms.cleaner, "cleaning program"},
  111.     {OPT_INT, "fsyncfreq", (char *)&parms.fsyncFreq, "Do fsync every N files"}
  112. };
  113. int numOptions = sizeof(optionArray) / sizeof(Option);
  114.  
  115.  
  116. /*
  117.  *----------------------------------------------------------------------
  118.  *
  119.  * main --
  120.  *
  121.  *    Main driver for jupdate program.
  122.  *
  123.  * Results:
  124.  *    none.
  125.  *
  126.  * Side effects:
  127.  *    none.
  128.  *
  129.  * Note: jupdate is invoked from the Jaquith switchboard process,
  130.  *       not from the command line. Argument 1 must be the fd of
  131.  *       the incoming pipe.
  132.  *
  133.  *----------------------------------------------------------------------
  134.  */
  135.  
  136. int
  137. main(argc, argv)
  138.     int argc;
  139.     char *argv[];
  140. {
  141.     int sock;
  142.     int retCode = 0;
  143.     int tBufStream;
  144.     int tHdrStream;
  145.     T_FileStat statInfo;
  146.     int byteCnt;
  147.     int hdrByteCnt;
  148.     char *archPath;
  149.     MetaInfo metaInfo;
  150.     VolInfo volInfo;
  151.     int remSpace;
  152.     FILE *indxStream = (FILE *)NULL;
  153.     FILE *metaStream = (FILE *)NULL;
  154.     char indxPath[2*T_MAXPATHLEN];
  155.     char newIndxPath[2*T_MAXPATHLEN];
  156.     char *entryPtr;
  157.     int  entrySize;
  158.     int curTBufId;
  159.     int dontArchive = 0;
  160.     char oldFileName[T_MAXPATHLEN];
  161.     int fileCnt = 0;
  162.     int skipCnt = 0;
  163.     char perm;
  164.     long blocksFree;
  165.     int percentUsed;
  166.     int memCnt = 0;
  167.     int userKBytes = 0;
  168.     int indxBytes = 0;
  169.     int i;
  170.     int filesSinceFsync = 0;
  171.     int filesSinceAck = 0;
  172.     ArchConfig archConfig;
  173.     time_t timeStamp;
  174.     Caller caller;
  175.     int ackFreq;
  176.  
  177.  
  178.     memDbg = fopen("/jaquith/jtest/jupdate.mem", "w");
  179.     MEM_CONTROL(1024*1024, memDbg, TRACEMEM+TRACECALLS+CHECKALLBLKS, 4096);
  180.  
  181.     argc = Opt_Parse(argc, argv, optionArray, numOptions, 0);
  182.  
  183.     sock = parms.sock;
  184.     jDebug = parms.debug;
  185.  
  186.     archPath = Str_Cat(3, parms.root, "/", parms.arch);
  187.     logPath = Str_Cat(3, archPath, "/", ARCHLOGFILE);
  188.     *indxPath = '\0';
  189.  
  190.     sprintf(printBuf,"Caller %s@%s, flags 0x%x\n",
  191.         parms.userName, parms.hostName, parms.flags);
  192.     Log_AtomicEvent("jupdate", printBuf, logPath);
  193.  
  194.     /* get the ack frequency */
  195.     Sock_ReadInteger(sock, &ackFreq);
  196.     if (ackFreq < 0) {
  197.     sprintf(printBuf,"Bad ack frequency: %d\n", ackFreq);
  198.     fprintf(stderr,"%s",printBuf);
  199.     Log_AtomicEvent("jupdate", printBuf, logPath);
  200.     Sock_SendRespHdr(sock, T_BADMSGFMT, syserr);
  201.     return -1;
  202.     }
  203.  
  204.     /* Authorize user to send data, or not, as the case may be */
  205.     if (VerifyClient(archPath, sock, &caller) != T_SUCCESS) {
  206.     exit(0);
  207.     }
  208.  
  209.     if (Admin_ReadArchConfig(archPath, &archConfig) != T_SUCCESS) {
  210.     sprintf(printBuf,"Admin_ReadArchConfig failed: errno %d\n", syserr);
  211.     fprintf(stderr,"%s",printBuf);
  212.     Log_AtomicEvent("jupdate", printBuf, logPath);
  213.     Sock_SendRespHdr(sock, T_ADMFAILED, syserr);
  214.     return -1;
  215.     }
  216.  
  217.     if (Admin_GetCurTBuf(archPath, &curTBufId) != T_SUCCESS) {
  218.     sprintf(printBuf,"Admin_GetCurTBuf failed: errno %d\n", syserr);
  219.     Log_AtomicEvent("jupdate", printBuf, logPath);
  220.     Sock_SendRespHdr(sock, T_ADMFAILED, syserr);
  221.     return -1;
  222.     }
  223.  
  224.     if ((metaStream=Admin_OpenMetaInfo(archPath, curTBufId)) == NULL) {
  225.     sprintf(printBuf,"Admin_OpenMetaInfo failed: errno %d\n", syserr);
  226.     Log_AtomicEvent("jupdate", printBuf, logPath);
  227.     Sock_SendRespHdr(sock, T_ADMFAILED, syserr);
  228.     return -1;
  229.     }
  230.  
  231.     if (Admin_ReadMetaInfo(metaStream, &metaInfo) != T_SUCCESS) {
  232.     sprintf(printBuf,"Admin_ReadMetaInfo failed: errno %d\n", syserr);
  233.     Log_AtomicEvent("jupdate", printBuf, logPath);
  234.     Sock_SendRespHdr(sock, T_ADMFAILED, syserr);
  235.     return -1;
  236.     }
  237.  
  238.     if (jDebug) {
  239.     fprintf(stderr,"jupdate: arch %s, tBufSize %d tHdrSize %d tBuf %d\n",
  240.         parms.arch, metaInfo.tBufSize, metaInfo.tHdrSize, curTBufId);
  241.     }
  242.  
  243.     if ((TBuf_Open(archPath, curTBufId,
  244.            &tBufStream, &tHdrStream, O_WRONLY) != T_SUCCESS) ||
  245.     (TBuf_Seek(tBufStream, metaInfo.tBufSize) != T_SUCCESS) ||
  246.     (TBuf_Seek(tHdrStream, metaInfo.tHdrSize) != T_SUCCESS)) {
  247.     sprintf(printBuf,"Couldn't open or seek tbuf: errno %d\n", syserr);
  248.     Log_AtomicEvent("jupdate", printBuf, logPath);
  249.     retCode = T_BUFFAILED;
  250.     }
  251.  
  252.     /*
  253.      * Must use a single timestamp for entire update operation,
  254.      * otherwise retrieval is messed up. Retrieving a directory omits
  255.      * some of its files because their timestamps are later than the
  256.      * parent's, making them look like a later version.
  257.      */
  258.     timeStamp = Time_GetCurDate();
  259.  
  260.     /*
  261.      * Now process the incoming files one by one.
  262.      * Each file is preceded by its meta information
  263.      */
  264.     while (retCode == T_SUCCESS) {
  265.     if (Sock_ReadFileStat(sock, &statInfo, 1) != T_SUCCESS) {
  266.         return T_BUFFAILED;
  267.     }
  268.     if (!*statInfo.fileName) {
  269.         break; /* we're done */
  270.     }
  271.  
  272.     filesSinceFsync++;
  273.     statInfo.vtime = timeStamp;
  274.     strcpy(oldFileName, statInfo.fileName);
  275.     Str_StripDots(statInfo.fileName);
  276.  
  277.     /* Open a new index file if its different from the current one */
  278.     Indx_MakeIndx(archPath, statInfo.fileName, newIndxPath);
  279.     if (strcmp(indxPath, newIndxPath) != 0) {
  280.         Indx_Close(indxStream);
  281.         strcpy(indxPath, newIndxPath);
  282.         retCode = Indx_Open(indxPath, "a", &indxStream);
  283.     }
  284.  
  285.     if (S_ISADIR(statInfo.mode)) {
  286.         statInfo.fileList = SortDirectoryList(statInfo.fileList);
  287.     }
  288.  
  289.     /* See if we really need to archive this file or not */
  290.     if (!(parms.flags & T_FORCE)) {
  291.         dontArchive = GetFileIndx(&statInfo, indxPath, archPath, &caller);
  292.         if ((Sock_WriteString(sock, oldFileName, 0) != T_SUCCESS) ||
  293.         (Sock_WriteInteger(sock, dontArchive) != T_SUCCESS)) {
  294.         sprintf(printBuf,"Couldn't confirm file %s: errno %d\n",
  295.             oldFileName, syserr);
  296.         Log_AtomicEvent("jupdate", printBuf, logPath);
  297.         retCode = T_BUFFAILED;
  298.         break;
  299.         } else if (dontArchive) {
  300.         skipCnt++;
  301.         if ((ackFreq > 0) && (++filesSinceAck >= ackFreq)) {
  302.             Sock_WriteString(sock, oldFileName, 0);
  303.             filesSinceAck = 0;
  304.         }
  305.         Utils_FreeFileStat(&statInfo, 0);
  306.         if (memCnt++ == 100) {
  307.             memCnt == 0;
  308.             MEM_REPORT("jupdate", ALLROUTINES, SORTBYREQ);
  309.         }
  310.         continue;
  311.         }
  312.     }
  313.     fileCnt++;
  314.  
  315.     /*
  316.      * Heuristic for deciding if we should start a new tbuf:
  317.      * If the new file will overflow the desired tbuf length
  318.      * by more than the overhead involved in a new tape buffer,
  319.      * then start a new one.
  320.      * (overhead = filemark size; ignores index entry space)
  321.      */
  322.     remSpace = archConfig.tBufSize - metaInfo.tBufSize;
  323.     if (statInfo.size-remSpace > T_FILEMARKSIZE) {
  324.         metaInfo.tBufPad =
  325.             TBuf_Close(tBufStream, tHdrStream, metaInfo.tBufSize);
  326.         Admin_WriteMetaInfo(metaStream, &metaInfo);
  327.         Admin_CloseMetaInfo(metaStream);
  328.         metaInfo.tBufSize = 0;
  329.         metaInfo.tHdrSize = T_TBLOCK;
  330.         metaInfo.fileCnt = 0;
  331.         metaInfo.tBufPad = 0;
  332.         Admin_SetCurTBuf(archPath, curTBufId+1);
  333.         Admin_OpenMetaInfo(archPath, curTBufId+1);
  334.         Admin_GetDiskUse(parms.root, &percentUsed, &blocksFree);
  335.         if ((parms.flags & T_SYNC) ||
  336.         (percentUsed >= parms.diskHigh)) {
  337.         FlushTBuf(curTBufId, &parms, archPath);
  338.         } else if (blocksFree < 2*(statInfo.size>>10)) {
  339.         parms.flags |= T_SYNC;
  340.         FlushTBuf(curTBufId, &parms, archPath);
  341.         parms.flags &= ~T_SYNC;
  342.         }
  343.         curTBufId++;
  344. /*
  345.         if (jDebug) {
  346.         sprintf(printBuf,"Starting tbuf.%d for %s\n",
  347.             curTBufId, statInfo.fileName);
  348.         Log_AtomicEvent("jupdate", printBuf, logPath);
  349.         }
  350. */
  351.         retCode = TBuf_Open(archPath, curTBufId,
  352.                 &tBufStream, &tHdrStream, O_WRONLY);
  353.         TBuf_Seek(tHdrStream, T_TBLOCK);
  354.     }
  355.  
  356.     /* Now copy in user's file into buffer */
  357.     if ((retCode=ReadOneFile(sock, tBufStream, &byteCnt, &statInfo))
  358.         != T_SUCCESS) {
  359.         sprintf(printBuf,"ReadOneFile failed: errno %d\n", syserr);
  360.         Log_AtomicEvent("jupdate", printBuf, logPath);
  361.         break;
  362.     }
  363.  
  364.     /* Update the header file and indx file */
  365.     statInfo.tBufId = curTBufId;
  366.     statInfo.offset = metaInfo.tBufSize;
  367.     if ((hdrByteCnt=Indx_WriteIndxEntry(&statInfo, 
  368.                         tHdrStream, indxStream)) <= 0) {
  369.         sprintf(printBuf,"Write of index info failed: errno %d\n", syserr);
  370.         Log_AtomicEvent("jupdate", printBuf, logPath);
  371.         retCode = T_IOFAILED;
  372.         break;
  373.     }
  374.  
  375.     metaInfo.tBufSize += byteCnt;
  376.     metaInfo.tHdrSize += hdrByteCnt;
  377.     metaInfo.fileCnt++;
  378.  
  379.     /* Sync this stuff to disk for safety, if requested */
  380.     if ((parms.fsyncFreq > 0) && (filesSinceFsync > parms.fsyncFreq)) {
  381.         fsync(tBufStream);
  382.         fsync(tHdrStream);
  383.         fsync(fileno(indxStream));
  384.     }
  385.  
  386.     /* If all went well, update the meta info to make it official */
  387.     if ((retCode=Admin_WriteMetaInfo(metaStream, &metaInfo)) != T_SUCCESS) {
  388.         sprintf(printBuf,"Admin_WriteMetaInfo failed: errno %d\n", syserr);
  389.         Log_AtomicEvent("jupdate", printBuf, logPath);
  390.         retCode = T_IOFAILED;
  391.         break;
  392.     }
  393.  
  394.     /* Sync this stuff to disk for safety, if requested */
  395.     if ((parms.fsyncFreq > 0) && (filesSinceFsync > parms.fsyncFreq)) {
  396.         fsync(fileno(metaStream));
  397.         filesSinceFsync = 0;
  398.     }
  399.  
  400.     userKBytes += byteCnt>>10;
  401.     indxBytes += hdrByteCnt;
  402.  
  403.     /* Acknowledge this stuff, if requested */
  404.     if ((ackFreq > 0) && (++filesSinceAck >= ackFreq)) {
  405.         Sock_WriteString(sock, oldFileName, 0);
  406.         filesSinceAck = 0;
  407.     }
  408.  
  409.     Utils_FreeFileStat(&statInfo, 0);
  410.  
  411.     if (memCnt++ == 100) {
  412.         memCnt == 0;
  413.         MEM_REPORT("jupdate", ALLROUTINES, SORTBYREQ);
  414.     }
  415.  
  416.     }
  417.  
  418.     Utils_FreeFileStat(&statInfo, 0);
  419.  
  420.     MEM_REPORT("jupdate", ALLROUTINES, SORTBYREQ);
  421.  
  422.     metaInfo.tBufPad = TBuf_Close(tBufStream, tHdrStream, metaInfo.tBufSize);
  423.     Admin_WriteMetaInfo(metaStream, &metaInfo);
  424.     Admin_CloseMetaInfo(metaStream);
  425.     if (indxStream) {
  426.     Indx_Close(indxStream);
  427.     }
  428.  
  429.     /* Flush final stuff if necessary */
  430.     if ((retCode == T_SUCCESS) && (parms.flags & T_SYNC)) {
  431.     Admin_SetCurTBuf(archPath, curTBufId+1);
  432.     FlushTBuf(curTBufId, &parms, archPath);
  433.     }
  434.  
  435.     Sock_SendRespHdr(sock, retCode, syserr);
  436.  
  437.     sprintf(printBuf,"Done. KBytes: user %d, indx %d. Files: put %d, skipped %d. RetCode %d, errno %d.\n",
  438.         userKBytes, indxBytes>>10, fileCnt, skipCnt, retCode, syserr);
  439.     Log_AtomicEvent("jupdate", printBuf, logPath);
  440.     if (jDebug) {
  441.     fprintf(stderr,"%s %s", parms.arch, printBuf);
  442.     }
  443.  
  444.     return retCode;
  445. }
  446.  
  447.  
  448. /*
  449.  *----------------------------------------------------------------------
  450.  *
  451.  * GetFileIndx --
  452.  *
  453.  *    Check indx to see if we really need to archive the file
  454.  *
  455.  * Results:
  456.  *      "don't archive flag".
  457.  *
  458.  * Side effects:
  459.  *    none.
  460.  *
  461.  *----------------------------------------------------------------------
  462.  */
  463.  
  464. static int
  465. GetFileIndx(statInfoPtr, indxPath, archPath, callerPtr)
  466.     T_FileStat *statInfoPtr;  /* File in question */
  467.     char *indxPath;           /* pathname of indx file */
  468.     char *archPath;           /* pathname of archive */
  469.     Caller *callerPtr;        /* caller id */
  470. {
  471.     static QuerySpec query = {
  472.     -1, -1,               /* versions */
  473.     (time_t)-1, (time_t)-1, /* dates */
  474.     "", "",               /* id's */
  475.     0,                    /* flags */
  476.     0,                    /* recursion */
  477.     (regexp *)NULL,       /* compiled abstract */
  478.     ""                    /* filename */
  479.     };
  480.     ReceiveBlk receiveBlk;
  481.     int retCode;
  482.  
  483.     query.fileName = STRRCHR(statInfoPtr->fileName, '/') + 1;
  484.     receiveBlk.statInfoPtr = statInfoPtr;
  485.  
  486.     retCode = Indx_Match(&query, indxPath, archPath, callerPtr,
  487.              ReceiveIndxProc, (int *)&receiveBlk, 0);
  488.     return retCode;
  489. }
  490.  
  491.  
  492. /*
  493.  *----------------------------------------------------------------------
  494.  *
  495.  * ReceiveIndxProc --
  496.  *
  497.  *    Accept data produced by indx code
  498.  *
  499.  * Results:
  500.  *      none.
  501.  *
  502.  * Side effects:
  503.  *    Sends info over socket to caller.
  504.  *
  505.  * Note:
  506.  *      This is a callback routine used by MatchVersionsProc in indx.
  507.  *
  508.  *----------------------------------------------------------------------
  509.  */
  510.  
  511. static int
  512. ReceiveIndxProc(oldInfoPtr, callVal)
  513.     T_FileStat *oldInfoPtr;   /* Index information */
  514.     int *callVal;             /* Callback info block */
  515. {
  516.     int dontArchive = 0;
  517.     ReceiveBlk *receiveBlkPtr = (ReceiveBlk *)callVal;
  518.     T_FileStat *statInfoPtr = receiveBlkPtr->statInfoPtr;
  519.     int oldMode = oldInfoPtr->mode;
  520.     int mode = statInfoPtr->mode;
  521.  
  522.     if (oldMode == mode) {
  523.     if (S_ISADIR(statInfoPtr->mode)) {
  524.         if (strcmp(statInfoPtr->fileList,oldInfoPtr->fileList) == 0) {
  525. /*
  526.         if (jDebug) {
  527.             fprintf(stderr, "RecvIndxProc: dir unchanged\n");
  528.         }
  529. */
  530.         dontArchive = 1;        
  531.         }
  532.     } else {
  533.         if (Time_Compare(statInfoPtr->mtime,oldInfoPtr->vtime,0) <= 0) {
  534. /*
  535.         if (jDebug) {
  536.             fprintf(stderr, "RecvIndxProc: file unchanged\n");
  537.         }
  538. */
  539.         dontArchive = 1;
  540.         }
  541.     }
  542.     }
  543.  
  544.     return dontArchive;
  545.  
  546. }
  547.  
  548.  
  549.  
  550. /*
  551.  *----------------------------------------------------------------------
  552.  *
  553.  * ReadOneFile --
  554.  *
  555.  *    Slurp a filename and its contents from socket into workFile
  556.  *
  557.  * Results:
  558.  *      return code.
  559.  *
  560.  * Side effects:
  561.  *    None.
  562.  *
  563.  *
  564.  *----------------------------------------------------------------------
  565.  */
  566.  
  567. static int
  568. ReadOneFile(sockStream, destStream, byteCntPtr, statInfoPtr)
  569.     int sockStream;           /* possible source descriptor */
  570.     int destStream;           /* destination descriptor */
  571.     int *byteCntPtr;          /* number of bytes written (updated) */
  572.     T_FileStat *statInfoPtr;  /* file information (updated) */
  573. {
  574.     int retCode = T_SUCCESS;
  575.     char buf[T_BUFSIZE];
  576.     int count;
  577.     int byteCnt;
  578.     int size = statInfoPtr->size;
  579.     int srcStream = sockStream;
  580.  
  581.     *byteCntPtr = 0;
  582.     byteCnt = TBuf_WriteTarHdr(destStream, statInfoPtr);
  583.  
  584. #ifdef sprite
  585.     if ((parms.flags & T_LOCAL) && (size > 0)) {
  586.     if ((srcStream=open(statInfoPtr->fileName, O_RDONLY, 0)) == -1) {
  587.         syserr = errno;
  588.         sprintf(printBuf,"Couldn't open file %s. errno %d\n",
  589.             statInfoPtr->fileName, syserr);
  590.         Log_AtomicEvent("jupdate", printBuf, logPath);
  591.         size = 0;
  592.     }
  593.     }
  594. #endif
  595.     while (size > 0) {
  596.     count = (size > sizeof(buf)) ? sizeof(buf) : size;
  597.     if (Sock_ReadNBytes(srcStream, buf, count) != count) {
  598.         sprintf(printBuf,"Read %d bytes for %s failed. errno %d\n",
  599.             count, statInfoPtr->fileName, syserr);
  600.         Log_AtomicEvent("jupdate", printBuf, logPath);
  601.         return T_IOFAILED;
  602.     }
  603.     if (write(destStream, buf, count) != count) {
  604.         sprintf(printBuf,"Write %d bytes for %s failed. errno %d\n",
  605.             count, statInfoPtr->fileName, syserr);
  606.         Log_AtomicEvent("jupdate", printBuf, logPath);
  607.         return T_IOFAILED;
  608.     }
  609.     size -= count;
  610.     byteCnt += count;
  611.     }
  612.  
  613. #ifdef sprite
  614.     if (srcStream != sockStream) {
  615.     close(srcStream);
  616.     }
  617. #endif
  618.  
  619.     count = TBuf_Pad(destStream, byteCnt, T_TBLOCK);
  620.     byteCnt += count;
  621.  
  622.     *byteCntPtr = byteCnt;
  623.  
  624.     return retCode;
  625. }
  626.  
  627.  
  628.  
  629. /*
  630.  *----------------------------------------------------------------------
  631.  *
  632.  * FlushTBuf --
  633.  *
  634.  *    Put tbuf out on media.
  635.  *
  636.  * Results:
  637.  *    None.
  638.  *
  639.  * Side effects:
  640.  *    Erases tbuf if space is below threshold.
  641.  *
  642.  *----------------------------------------------------------------------
  643.  */
  644.  
  645. static int
  646. FlushTBuf(tBufId, parmsPtr, archPath)
  647.     int tBufId;               /* buffer Identifier */
  648.     Parms *parmsPtr;          /* parameter block */
  649.     char *archPath;           /* current archive */
  650. {
  651.     int pid;
  652.     union wait status;
  653.     char buf[20];
  654.     char buf2[20];
  655.     char buf3[20];
  656.  
  657.     if (jDebug) {
  658.     fprintf(stderr,"FlushTBuf: flushing %d\n", tBufId);
  659.     }
  660.  
  661.     /*
  662.      * If sync not needed and a cleaner already exists we're done.
  663.      * There's a race here but it doesn't matter; sync hasn't been
  664.      * requested and the buffer will go out by the timed cleaner later.
  665.      */
  666.     if (!(parmsPtr->flags & T_SYNC) && (!Admin_AvailVolInfo(archPath))) {
  667.     return T_SUCCESS;
  668.     }
  669.  
  670.     /* Remove any dead beasties ... */
  671.     ReapChildren();
  672.  
  673.     /* Need to fork a cleaner process */
  674.     if ((pid=fork()) == -1) {
  675.     syserr = errno;
  676.     sprintf(printBuf, "Couldn't fork cleaner. errno %d\n", syserr);
  677.     Log_AtomicEvent("FlushTBuf", printBuf, logPath);
  678.     return T_FAILURE;
  679.     } else if (pid == 0) {
  680.     MEM_CONTROL(0, NULL, 0, 0);
  681.     close(parmsPtr->sock);
  682.     sprintf(buf, "%d", tBufId);
  683.     sprintf(buf2, "%d", parmsPtr->diskLow);
  684.     sprintf(buf3, "%d", parmsPtr->diskHigh);
  685.     execlp(parmsPtr->cleaner, parmsPtr->cleaner,
  686.            "-root", parmsPtr->root,
  687.            "-arch", parmsPtr->arch,
  688.            "-tbufid", buf,
  689.            "-disklow", buf2,
  690.            "-diskhigh", buf3,
  691.            "-username", parmsPtr->userName,
  692.            "-hostname", parmsPtr->hostName,
  693.            "-debug", (jDebug) ? "1" : "0",
  694.            "-newvol", (parmsPtr->flags & T_NEWVOL) ? "1" : "0",
  695.            NULL);
  696.     sprintf(printBuf, "Failed to exec %s: errno %d\n",
  697.         parmsPtr->cleaner, errno);
  698.     Log_AtomicEvent("FlushTBuf", printBuf, logPath);
  699.     _exit(-1);
  700.     }
  701.  
  702.     parmsPtr->flags &= ~T_NEWVOL;
  703.  
  704.     /* wait around if we were so instructed ... */
  705.     if ((parmsPtr->flags & T_SYNC) &&
  706.     ((wait(&status) != pid) || (status.w_T.w_Retcode != 0))) {
  707.     syserr = errno;
  708.     sprintf(printBuf,"Cleaner retcode %d. Wait errno %d\n",
  709.         status.w_T.w_Retcode, syserr);
  710.     Log_AtomicEvent("FlushTBuf", printBuf, logPath);
  711.     return T_FAILURE;
  712.     } else {
  713.     return T_SUCCESS;
  714.     }
  715. }
  716.  
  717.  
  718. /*
  719.  *----------------------------------------------------------------------
  720.  *
  721.  * SortDirectoryList --
  722.  *
  723.  *    Put directory list in canonical form.
  724.  *
  725.  * Results:
  726.  *    Return code.
  727.  *
  728.  * Side effects:
  729.  *    Allocates space for sorted list.
  730.  *
  731.  * Note:
  732.  *      Canonical form is comma-separated, sorted list
  733.  *      of names surrounded by curlies. This is so Str_Match
  734.  *      will do the right thing.
  735.  *
  736.  *----------------------------------------------------------------------
  737.  */
  738.  
  739. static char *
  740. SortDirectoryList(list)
  741.     char *list;               /* list of items to be sorted */
  742. {
  743.     char **partsList;
  744.     int partsCnt;
  745.     char *bufPtr = NULL;
  746.     char *workPtr;
  747.     char *quotedString;
  748.     int len;
  749.     int i;
  750.     char *insidePtr;
  751.  
  752.     quotedString = Str_Quote(list, METACHARS);
  753.     MEM_FREE("SortDirectoryList", list);
  754.     len = strlen(quotedString) + 3;
  755.     partsList = Str_Split(quotedString, ' ', &partsCnt, 1, &insidePtr);
  756.     MEM_FREE("SortDirectoryList", quotedString);
  757.  
  758.     if (partsCnt > 0) {
  759.     qsort((char *)partsList, partsCnt, sizeof(char *), StringCompareProc);
  760.     workPtr = bufPtr = MEM_ALLOC("SortDirectoryList", len);
  761.  
  762.     *workPtr++ = '{';
  763.     for (i=0; i<partsCnt; i++) {
  764.         strcpy(workPtr, partsList[i]);
  765.         workPtr += strlen(partsList[i]);
  766.         *workPtr++ = ',';
  767.     }
  768.     *(workPtr-1) = '}';
  769.     *workPtr = '\0';
  770.     } else {
  771.     bufPtr = Str_Dup("{}");
  772.     }
  773.  
  774.     MEM_FREE("SortDirectoryList", partsList);
  775.     MEM_FREE("SortDirectoryList", insidePtr);
  776.  
  777.     return bufPtr;
  778. }
  779.  
  780.  
  781. /*
  782.  *----------------------------------------------------------------------
  783.  *
  784.  * StringCompareProc --
  785.  *
  786.  *    Compare to string pointers.
  787.  *
  788.  * Results:
  789.  *    <1, 0, >1
  790.  *
  791.  * Side effects:
  792.  *    None.
  793.  *
  794.  * Note:
  795.  *      This is a callback routine used by qsort.
  796.  *
  797.  *----------------------------------------------------------------------
  798.  */
  799.  
  800. static int
  801. StringCompareProc(a, b)
  802.     char **a;                 /* string item 1 */
  803.     char **b;                 /* string item 2 */
  804. {
  805.     return strcmp(*a, *b);
  806. }
  807.  
  808.  
  809. /*
  810.  *----------------------------------------------------------------------
  811.  *
  812.  * ReapChildren --
  813.  *
  814.  *    Collect cadavers
  815.  *
  816.  * Results:
  817.  *    none.
  818.  *
  819.  * Side effects:
  820.  *    Reaps cleaner child.
  821.  *
  822.  * Note:
  823.  *      Catching children with sigchld would interrupt all the socket
  824.  *      I/O going on and I don't want to have to restart that stuff.
  825.  *
  826.  *----------------------------------------------------------------------
  827.  */
  828.  
  829. static void
  830. ReapChildren()
  831. {
  832.     int pid;
  833.     union wait wstatus;
  834.  
  835.     while ((pid=wait3(&wstatus, WNOHANG, NULL)) > 0) {
  836.     if (wstatus.w_T.w_Retcode != 0) {
  837.         sprintf(printBuf,"Cleaner retcode %d\n",
  838.             wstatus.w_T.w_Retcode);
  839.         Log_AtomicEvent("Jupdate", printBuf, logPath);
  840.     }
  841.     }
  842. }
  843.  
  844.  
  845. /*
  846.  *----------------------------------------------------------------------
  847.  *
  848.  * VerifyClient --
  849.  *
  850.  *    Check authorization of client for this archive
  851.  *
  852.  * Results:
  853.  *    return Code
  854.  *
  855.  * Side effects:
  856.  *    Sends negative ack if not authorized else send go-ahead msg.
  857.  *      Builds Caller structure for future use.
  858.  *
  859.  *----------------------------------------------------------------------
  860.  */
  861.  
  862. static int
  863. VerifyClient(archPath, sock, callerPtr)
  864.     char *archPath;           /* archive pathname */
  865.     int sock;                 /* caller socket */
  866.     Caller *callerPtr;        /* caller id */
  867. {
  868.     int retCode;
  869.     char perm;
  870.  
  871.     callerPtr->userName = Str_Dup(parms.userName);
  872.     callerPtr->hostName = Str_Dup(parms.hostName);
  873.     callerPtr->groupName = Str_Dup(parms.groupName);
  874.  
  875.     if ((retCode=Admin_CheckAuth(archPath, callerPtr, &perm)) != T_SUCCESS) {
  876.     sprintf(printBuf,"Admin_CheckAuth failed: errno %d\n", syserr);
  877.     Log_AtomicEvent("jupdate", printBuf, logPath);
  878.     Sock_SendRespHdr(sock, retCode, syserr);
  879.     return T_NOACCESS;
  880.     }
  881.  
  882.     if ((perm != 'W') && (perm != 'O')) {
  883.     sprintf(printBuf,"Access denied: %s %s from %s\n",
  884.         parms.userName, parms.groupName, parms.hostName);
  885.     Log_AtomicEvent("jupdate", printBuf, logPath);
  886.     Sock_SendRespHdr(sock, T_NOACCESS, 0);
  887.     return T_NOACCESS;
  888.     }
  889.  
  890.     /* Give the go-ahead message */
  891.     Sock_SendRespHdr(sock, T_SUCCESS, 0);
  892.  
  893.     /*
  894.      * if user is owner, change his name to '*' so Str_Match succeeds.
  895.      */
  896.     if (perm == 'O') {
  897.     *(callerPtr->userName) = '*';
  898.     *(callerPtr->userName+1) = '\0';
  899.     }
  900.  
  901.     return T_SUCCESS;
  902. }
  903.  
  904. /* debug only */
  905. static int
  906. GetIncTime(init)
  907.     int init;
  908. {
  909.     static struct timeval lastTime;
  910.     static struct timeval curTime;
  911.     int sec,usec;
  912.  
  913.     if (init) {
  914.         gettimeofday(&lastTime, NULL);
  915.     return 0;
  916.     } else {
  917.         gettimeofday(&curTime, NULL);
  918.     sec = curTime.tv_sec - lastTime.tv_sec;
  919.     if (curTime.tv_usec < lastTime.tv_usec) {
  920.       sec--;
  921.       usec = 1000000 - (lastTime.tv_usec - curTime.tv_usec);
  922.     } else {
  923.       usec = curTime.tv_usec - lastTime.tv_usec;
  924.         }
  925. /*
  926.     fprintf(stderr,"last: %x %x\n cur: %x %x\n",
  927.         lastTime.tv_sec, lastTime.tv_usec,
  928.         curTime.tv_sec, curTime.tv_usec);
  929. */
  930.     lastTime = curTime;
  931.     return (sec*1000+usec/1000);
  932.     }
  933. }
  934.  
  935. /* debug only */
  936. static int
  937. GetMsecs()
  938. {
  939.     static struct timeval curTime;
  940.     int sec,usec;
  941.  
  942.     gettimeofday(&curTime, NULL);
  943.     return (curTime.tv_sec*1000+curTime.tv_usec/1000);
  944. }
  945.